home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / utils / nroff~06.zoo / low.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-16  |  16.7 KB  |  1,102 lines

  1. static char *rcsid_low_c="$Id: low.c,v 1.2 1992/07/16 10:38:32 rosenkra Exp $";
  2.  
  3. /*
  4.  * $Log: low.c,v $
  5.  * Revision 1.2  1992/07/16  10:38:32  rosenkra
  6.  * port to gcc, add tm,ie,el
  7.  *
  8.  */
  9.  
  10. /*
  11.  *    low.c - misc low-level functions for nroff word processor
  12.  *
  13.  *    adapted for atariST/TOS by Bill Rosenkranz 11/89
  14.  *    net:    rosenkra@convex.com
  15.  *    CIS:    71460,17
  16.  *    GENIE:    W.ROSENKRANZ
  17.  *
  18.  *    original author:
  19.  *
  20.  *    Stephen L. Browning
  21.  *    5723 North Parker Avenue
  22.  *    Indianapolis, Indiana 46220
  23.  *
  24.  *    history:
  25.  *
  26.  *    - Originally written in BDS C;
  27.  *    - Adapted for standard C by W. N. Paul
  28.  *    - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz
  29.  */
  30.  
  31. #undef NRO_MAIN                    /* extern globals */
  32.  
  33. #include <stdio.h>
  34. #include "nroff.h"
  35.  
  36.  
  37.  
  38. /*------------------------------*/
  39. /*    atod            */
  40. /*------------------------------*/
  41. int atod (c)
  42. char    c;
  43. {
  44.  
  45. /*
  46.  *    convert ascii character to decimal.
  47.  */
  48.  
  49.     return (((c < '0') || (c > '9')) ? -1 : c - '0');
  50. }
  51.  
  52.  
  53.  
  54.  
  55.  
  56. /*------------------------------*/
  57. /*    robrk            */
  58. /*------------------------------*/
  59. void robrk ()
  60. {
  61.  
  62. /*
  63.  *    end current filled line
  64.  */
  65.  
  66.     REGISTER char  *p, *p0;
  67.  
  68.     if (co.outp > 0)
  69.     {
  70.         /*
  71.          *   kill trailing blanks....
  72.          */
  73.         p0 = &(co.outbuf[0]);
  74.         p  = &(co.outbuf[co.outp]);
  75.         for (p--; (long) p > (long) p0; p--)
  76.         {
  77.             if (*p != ' ' && *p != '\t')
  78.                 break;
  79.             co.outp -= 1;            
  80.         }
  81.  
  82.  
  83.         /*
  84.          *   terminate line
  85.          */
  86. #ifdef NO_CR
  87.         co.outbuf[co.outp]   = '\n';
  88.         co.outbuf[co.outp+1] = EOS;
  89. #else
  90.         co.outbuf[co.outp]   = '\r';
  91.         co.outbuf[co.outp+1] = '\n';
  92.         co.outbuf[co.outp+2] = EOS;
  93. #endif
  94.  
  95.         /*
  96.          *   handle margin char (change bar) here for all filled lines
  97.          */
  98.         do_mc (co.outbuf);
  99.  
  100.         put (co.outbuf);
  101.     }
  102.     co.outp   = 0;
  103.     co.outw   = 0;
  104.     co.outwds = 0;
  105.     co.outesc = 0;
  106. }
  107.  
  108.  
  109.  
  110.  
  111. /*------------------------------*/
  112. /*    ctod            */
  113. /*------------------------------*/
  114. int ctod (p)
  115. REGISTER char  *p;
  116. {
  117.  
  118. /*
  119.  *    convert string to decimal. processes only positive values.
  120.  *    this takes a constant like "1", "1.0i", etc. 
  121.  */
  122.  
  123.     REGISTER long    val;
  124.     REGISTER int    d;
  125.     REGISTER char  *pp = p;
  126.     REGISTER char  *ptmp;
  127.     int        rside = 0;
  128.     int        lside = 0;
  129.     int        has_rside = 0;
  130.     int        has_lside = 0;
  131.  
  132.     if (*p == EOS)
  133.         return (0);
  134.  
  135.     ptmp = skipwd (pp);
  136.     pp = --ptmp;
  137.     
  138.     switch (*pp)
  139.     {
  140.     case 'i':
  141.     case 'c':
  142.         val = 0L;
  143.         while (*p != EOS && isdigit (*p))
  144.         {
  145.             has_lside++;
  146.             lside = atod (*p);
  147.             p++;
  148.             if (lside == -1)
  149.                 break;
  150.             val = 10L * val + (long) lside;
  151.         }
  152.         lside = (int) val;
  153.         if (*p == '.')
  154.         {
  155.             p++;
  156.             val = 0L;
  157.             while (*p != EOS && isdigit (*p))
  158.             {
  159.                 has_rside++;
  160.                 rside = atod (*p);
  161.                 p++;
  162.                 if (rside == -1)
  163.                     break;
  164.                 val = 10L * val + (long) rside;
  165.                 if (has_rside > 2)    /* more than enough */
  166.                     break;
  167.             }
  168.             rside = (int) val;
  169.         }
  170.  
  171.         /*
  172.          *   now put it together. 1.0i -> 240, 1.50i -> 360, etc.
  173.          */
  174.         val = 0L;
  175.         if (has_lside)
  176.         {
  177.             val = (long) lside * BU_INCH;
  178.         }
  179.         switch (has_rside)
  180.         {
  181.         case 1:
  182.             val = val + ((long) rside * BU_INCH / 10L);
  183.             break;
  184.         case 2:
  185.             val = val + ((long) rside * BU_INCH / 100L);
  186.             break;
  187.         case 3:
  188.             val = val + ((long) rside * BU_INCH / 1000L);
  189.             break;
  190.         default:
  191.             break;
  192.         }
  193.         if (*pp == 'c')
  194.             val = (val * BU_CM) / BU_INCH;
  195.  
  196.         /*
  197.          *   for now we convert to basic char size, 1 em...
  198.          */
  199.         val = val / BU_EM;
  200.  
  201.         break;
  202.  
  203.     case 'P':
  204.     case 'm':
  205.     case 'n':
  206.     case 'p':
  207.     case 'u':
  208.     case 'v':
  209.         val = 0L;
  210.         while (*p != EOS)
  211.         {
  212.             d = atod (*p);
  213.             p++;
  214.             if (d == -1)
  215.                 break;
  216.             val = 10L * val + (long) d;
  217.         }
  218.         switch (*pp)
  219.         {
  220.         case 'P':
  221.             val = val * BU_PICA;
  222.             break;
  223.         case 'p':
  224.             val = val * BU_POINT;
  225.             break;
  226.         case 'u':
  227.             val = val * BU_BU;
  228.             break;
  229.         case 'm':
  230.             val = val * BU_EM;
  231.             break;
  232.         case 'n':
  233.             val = val * BU_EN;
  234.             break;
  235.         case 'v':
  236.             val = val * BU_EM;
  237.             break;
  238.         }
  239.  
  240.         /*
  241.          *   for now we convert to basic char size, 1 em...
  242.          */
  243.         val = val / BU_EM;
  244.  
  245.         break;
  246.  
  247.     default:
  248.         /*
  249.          *   this is the default behavior. it SHOULD make things
  250.          *   compatible with the old way...
  251.          */
  252.         val = 0L;
  253.         while (*p != EOS)
  254.         {
  255.             d = atod (*p);
  256.             p++;
  257.             if (d == -1)
  258.                 break;
  259.             val = 10L * val + (long) d;
  260.         }
  261.         break;
  262.     }
  263.  
  264.     return ((int) val);
  265. }
  266.  
  267.  
  268.  
  269.  
  270. /*------------------------------*/
  271. /*    inptobu            */
  272. /*------------------------------*/
  273. void inptobu (ps)
  274. char   *ps;
  275. {
  276.  
  277. /*
  278.  *    convert input units to b.u.
  279.  */
  280.  
  281.     return;
  282. }
  283.  
  284.  
  285.  
  286.  
  287. /*------------------------------*/
  288. /*    butochar        */
  289. /*------------------------------*/
  290. void butochar (ps)
  291. char   *ps;
  292. {
  293.  
  294. /*
  295.  *    convert b.u. to char spaces
  296.  */
  297.  
  298.     return;
  299. }
  300.  
  301.  
  302.  
  303.  
  304. /*------------------------------*/
  305. /*    skipbl            */
  306. /*------------------------------*/
  307. char *skipbl (p)
  308. REGISTER char  *p;
  309. {
  310.  
  311. /*
  312.  *    skip blanks and tabs in character buffer. return ptr to first
  313.  *    non-space or non-tab char. this could mean EOS or \r or \n.
  314.  *    also increments the arg ptr (side effect).
  315.  */
  316.  
  317.     while ((*p != EOS) && (*p == ' ' || *p == '\t'))
  318.         ++p;
  319.     return (p);
  320. }
  321.  
  322.  
  323.  
  324.  
  325. /*------------------------------*/
  326. /*    skipwd            */
  327. /*------------------------------*/
  328. char *skipwd (p)
  329. REGISTER char  *p;
  330. {
  331.  
  332. /*
  333.  *    skip over word and punctuation. anything but space,\t,\r,\n, and EOS
  334.  *    is skipped. return ptr to the first of these found. also increments
  335.  *    the arg ptr (side effect).
  336.  */
  337.  
  338.     while (*p != EOS && *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n')
  339.         ++p;
  340.     return (p);
  341. }
  342.  
  343.  
  344.  
  345.  
  346.  
  347. /*------------------------------*/
  348. /*    space            */
  349. /*------------------------------*/
  350. void space (n)
  351. int     n;
  352. {
  353.  
  354. /*
  355.  *    space vertically n lines. this does header and footer also.
  356.  */
  357.  
  358.     robrk ();
  359.     if (pg.lineno > pg.bottom)
  360.         return;
  361.     if (pg.lineno == 0)
  362.         phead ();
  363.     skip (min (n, pg.bottom + 1 - pg.lineno));
  364.     pg.lineno += n;
  365.     set_ireg ("ln", pg.lineno, 0);
  366.     if (pg.lineno > pg.bottom)
  367.         pfoot ();
  368. }
  369.  
  370.  
  371.  
  372.  
  373. /*------------------------------*/
  374. /*    getfield        */
  375. /*------------------------------*/
  376. char *getfield (p, q, delim)
  377. REGISTER char  *p;
  378. REGISTER char  *q;
  379. char        delim;
  380. {
  381.  
  382. /*
  383.  *    get field from title
  384.  */
  385.  
  386.     while (*p != delim && *p != '\r' && *p != '\n' && *p != EOS)
  387.     {
  388.         *q++ = *p++;
  389.     }
  390.     *q = EOS;
  391.     if (*p == delim)
  392.         ++p;
  393.     return (p);
  394. }
  395.  
  396.  
  397.  
  398.  
  399.  
  400. /*------------------------------*/
  401. /*    getwrd            */
  402. /*------------------------------*/
  403. int getwrd (p0, p1)
  404. REGISTER char  *p0;
  405. REGISTER char  *p1;
  406. {
  407.  
  408. /*
  409.  *    get non-blank word from p0 into p1.
  410.  *    return number of characters processed.
  411.  */
  412.  
  413.     REGISTER int    i;
  414.     REGISTER char  *p;
  415.     char        c;
  416.  
  417.     /*
  418.      *   init counter...
  419.      */
  420.     i = 0;
  421.  
  422.  
  423.     /*
  424.      *   skip leading whitespace
  425.      */
  426.     while (*p0 && (*p0 == ' ' || *p0 == '\t'))
  427.     {
  428.         ++i;
  429.         ++p0;
  430.     }
  431.  
  432.  
  433.     /*
  434.      *   set ptr and start to look for end of word
  435.      */
  436.     p = p0;
  437.     while (*p0 != ' ' && *p0 != EOS && *p0 != '\t')
  438.     {
  439.         if (*p0 == '\n' || *p0 == '\r')
  440.             break;
  441.         *p1 = *p0++;
  442.         ++p1;
  443.         ++i;
  444.     }
  445.  
  446.     c = *(p1 - 1);
  447.     if (c == '\"')
  448.         c = *(p1 - 2);
  449.     if (c == '?' || c == '!')
  450.     {
  451.         *p1++ = ' ';
  452.         ++i;
  453.     }
  454.     if (c == '.' && (*p0 == '\n' || *p0 == '\r' || islower (*p)))
  455.     {
  456.         *p1++ = ' ';
  457.         ++i;
  458.     }
  459.     *p1 = EOS;
  460.  
  461.     return (i);
  462. }
  463.  
  464.  
  465.  
  466.  
  467. /*------------------------------*/
  468. /*    countesc        */
  469. /*------------------------------*/
  470.  
  471. #define ESC            27
  472.  
  473. int countesc (p)
  474. REGISTER char  *p;
  475. {
  476.  
  477. /*
  478.  *    count escape sequence characters in given null-terminated string.
  479.  *    we try and interpret the escape sequence, and if we recognize it,
  480.  *    we count the total number of chars in the sequence, including the
  481.  *    ESC itself. e.g. "ESC [ 1 m" is 4. we do this for the entire string.
  482.  *
  483.  *    the results are used when adjusting the margins, so we ignore the
  484.  *    additional chars added. the escape sequence should not be broken
  485.  *    up by this process, since we only add extra space(s) next to a
  486.  *    space.
  487.  */
  488.  
  489.     REGISTER char  *pp;
  490.     REGISTER int    num;
  491.  
  492.  
  493.     /*
  494.      *  initialize string pointer and count
  495.      */
  496.     pp  = p;
  497.     num = 0;
  498.  
  499.  
  500.     /*
  501.      *   do entire string...
  502.      */
  503.     while (*pp != EOS)
  504.     {
  505.         /*
  506.          *   is current char an ESC?
  507.          */
  508.         if (*pp == ESC)
  509.         {
  510.             /*
  511.              *   yes...
  512.              *
  513.              *   look at first char after the ESC and try to see
  514.              *   if we grok it...
  515.              */
  516.             switch (*(pp+1))
  517.             {
  518.             /*
  519.              *   this is atari/vt52-specific. escapes are 2, 3,
  520.              *   or 4 chars long. others we do not grok.
  521.              *   generally only p, q, b, and c will show up.
  522.              *   if we grok, advance pp ptr (see note below)
  523.              */
  524.             case 'A':            /* vt52: ESC x */
  525.             case 'B':
  526.             case 'C':
  527.             case 'D':
  528.             case 'E':
  529.             case 'H':
  530.             case 'I':
  531.             case 'J':
  532.             case 'K':
  533.             case 'L':
  534.             case 'M':
  535.             case 'd':
  536.             case 'e':
  537.             case 'f':
  538.             case 'j':
  539.             case 'k':
  540.             case 'l':
  541.             case 'o':
  542.             case 'p':
  543.             case 'q':
  544.             case 'v':
  545.             case 'w':
  546.                 num += 2;
  547. /*!!!*/                pp  += 1;
  548.                 break;
  549.             case 'b':            /* vt52: ESC x x */
  550.             case 'c':
  551.                 num += 3;
  552. /*!!!*/                pp  += 1;
  553.                 break;
  554.             case 'Y':            /* vt52: ESC x x x */
  555.                 num += 4;
  556. /*!!!*/                pp  += 3;
  557.                 break;
  558.  
  559.  
  560.             /*
  561.              *   the only escapes like this that nroff itself
  562.              *   generates are these. others we can only guess
  563.              *   at, and we guess ESC [ x x.
  564.              *
  565.              *   note: we advance pp to the end of the escape
  566.              *   to speed up the process. pp points to the ESC
  567.              *   initially. pp increment at the bottom of the
  568.              *   while will put us on the first char after the
  569.              *   escape...
  570.              */
  571.             case '[':            /* ansi: ESC [ ... */
  572.                 if (*(pp+2) == 'm')    /*       ESC [ m   */
  573.                 {
  574.                     num += 3;
  575. /*!!!*/                    pp  += 2;
  576.                 }
  577.                 else            /*       ESC [ n m */
  578.                 {
  579.                     num += 4;
  580. /*!!!*/                    pp  += 3;
  581.                 }
  582.                 break;
  583.  
  584.  
  585.             /*
  586.              *   it IS an escape, but we do not know it. so count
  587.              *   the escape itself, and treat what follows like
  588.              *   text
  589.              */
  590.             default:            /* unknown */
  591.                 num += 1;
  592.                 break;
  593.             }
  594.         }
  595.  
  596.  
  597.         /*
  598.          *   next char in string...
  599.          */
  600.         pp++;
  601.     }
  602.  
  603.  
  604.     /*
  605.      *   give caller the count
  606.      */
  607.     return (num);
  608. }
  609.  
  610.  
  611.  
  612.  
  613. /*------------------------------*/
  614. /*    itoda            */
  615. /*------------------------------*/
  616. int itoda (value, p, size)
  617. int        value;
  618. REGISTER char  *p;
  619. REGISTER int    size;
  620. {
  621.  
  622. /*
  623.  *    convert integer to decimal ascii string
  624.  */
  625.  
  626.     REGISTER int    i;
  627.     REGISTER int    j;
  628.     REGISTER int    aval;
  629.     char        c[20];
  630.  
  631.     aval = abs (value);
  632.     c[0] = EOS;
  633.     i = 1;
  634.     do
  635.     {
  636.         c[i++] = (aval % 10) + '0';
  637.         aval /= 10;
  638.  
  639.     } while (aval > 0 && i <= size);
  640.  
  641.     if (value < 0 && i <= size)
  642.         c[i++] = '-';
  643.     for (j = 0; j < i; ++j)
  644.         *p++ = c[i - j - 1];
  645.  
  646.     return (i);
  647. }
  648.  
  649.  
  650.  
  651.  
  652. /*------------------------------*/
  653. /*    itoROMAN        */
  654. /*------------------------------*/
  655. int itoROMAN (value, p, size)
  656. int        value;
  657. REGISTER char  *p;
  658. REGISTER int    size;
  659. {
  660.  
  661. /*
  662.  *    convert integer to upper roman. must be positive
  663.  */
  664.  
  665.     REGISTER int    i;
  666.     REGISTER int    j;
  667.     REGISTER int    aval;
  668.     char        c[100];
  669.     int        rem;
  670.  
  671.     aval = abs (value);
  672.     c[0] = EOS;
  673.     i = 1;
  674.  
  675.     /*
  676.      *   trivial case:
  677.      */
  678.     if (aval == 0)
  679.     {
  680.         c[i++] = '0';
  681.         goto done_100;
  682.     }
  683.  
  684.     /*
  685.      *   temporarily mod 100...
  686.      */
  687.     aval = aval % 100;
  688.  
  689.     if (aval > 0)
  690.     {
  691.         /*
  692.          *   build backward
  693.          *
  694.          *   | I|        1
  695.          *   | II|        2
  696.          *   | III|        3
  697.          *   | VI|        4
  698.          *   | V|        5
  699.          *   | IV|        6
  700.          *   | IIV|        7
  701.          *   | IIIV|        8
  702.          *   | XI|        9
  703.          *   | X|        0
  704.          *   | IX|        11
  705.          *   | IIX|        12
  706.          */
  707.         if ((aval % 5 == 0) && (aval % 10 != 0))/* 5 */
  708.             c[i++] = 'V';
  709.         else
  710.         {
  711.             rem = aval % 10;
  712.             if (rem == 9)            /* 9 */
  713.             {
  714.                 c[i++] = 'X';
  715.                 c[i++] = 'I';
  716.             }
  717.             else if (rem == 8)        /* 8 */
  718.             {
  719.                 c[i++] = 'I';
  720.                 c[i++] = 'I';
  721.                 c[i++] = 'I';
  722.                 c[i++] = 'V';
  723.             }
  724.             else if (rem == 7)        /* 7 */
  725.             {
  726.                 c[i++] = 'I';
  727.                 c[i++] = 'I';
  728.                 c[i++] = 'V';
  729.             }
  730.             else if (rem == 6)        /* 6 */
  731.             {
  732.                 c[i++] = 'I';
  733.                 c[i++] = 'V';
  734.             }
  735.             else if (rem == 4)        /* 4 */
  736.             {
  737.                 c[i++] = 'V';
  738.                 c[i++] = 'I';
  739.             }
  740.             else                /* 3,2,1 */
  741.             {
  742.                 for (j = 0; j < rem; j++)
  743.                     c[i++] = 'I';
  744.             }
  745.         }
  746.  
  747.         aval /= 10;
  748.         if (aval == 0)
  749.             goto done_100;
  750.  
  751.         rem = aval % 10;
  752.         if (rem == 4)
  753.         {
  754.             c[i++] = 'L';
  755.             c[i++] = 'X';
  756.         }
  757.         else if (rem == 5)
  758.         {
  759.             c[i++] = 'L';
  760.         }
  761.         else if (rem < 4)
  762.         {
  763.             for (j = 0; j < rem; j++)
  764.                 c[i++] = 'X';
  765.         }
  766.         else
  767.         {
  768.             for (j = 0; j < rem - 5; j++)
  769.                 c[i++] = 'X';
  770.             c[i++] = 'L';
  771.         }
  772.     }
  773.  
  774.  
  775. done_100:
  776.     /*
  777.      *   divide by 100 (they are done) and temp mod by another 10
  778.      */
  779.     aval  = abs (value);
  780.     aval /= 100;
  781.  
  782.     if (aval > 0)
  783.     {
  784.         rem  = aval % 10;
  785.         if (rem == 4)
  786.         {
  787.             c[i++] = 'D';
  788.             c[i++] = 'C';
  789.         }
  790.         if (rem == 5)
  791.         {
  792.             c[i++] = 'D';
  793.         }
  794.         else if (rem < 4)
  795.         {
  796.             for (j = 0; j < rem; j++)
  797.                 c[i++] = 'C';
  798.         }
  799.         else if (rem == 9)
  800.         {
  801.             c[i++] = 'M';
  802.             c[i++] = 'C';
  803.         }
  804.         else if (rem < 9)
  805.         {
  806.             for (j = 0; j < rem - 5; j++)
  807.                 c[i++] = 'C';
  808.             c[i++] = 'D';
  809.         }
  810.     }
  811.  
  812.  
  813.     aval /= 10;
  814.  
  815.     if (aval > 0)
  816.     {
  817.         rem  = aval % 10;
  818.         if (rem < 4)
  819.         {
  820.             for (j = 0; j < rem; j++)
  821.                 c[i++] = 'M';
  822.         }
  823.     }
  824.  
  825.  
  826.     if (value < 0)
  827.         c[i++] = '-';
  828.  
  829.     for (j = 0; j < i; ++j)
  830.         *p++ = c[i - j - 1];
  831.  
  832.     return (i);
  833. }
  834.  
  835.  
  836.  
  837.  
  838. /*------------------------------*/
  839. /*    itoroman        */
  840. /*------------------------------*/
  841. int itoroman (value, p, size)
  842. int     value;
  843. char   *p;
  844. int     size;
  845. {
  846.  
  847. /*
  848.  *    convert integer to lower roman
  849.  */
  850.  
  851.     REGISTER int    i;
  852.     REGISTER int    len;
  853.     char        c[100];
  854.  
  855.     c[0] = EOS;
  856.     len = itoROMAN (value, c, size);
  857.  
  858.     for (i = 0; i < len; i++)
  859.     {
  860.         p[i] = c[i];
  861.         if (isalpha (p[i]))
  862.             p[i] = tolower (c[i]);
  863.     }
  864.  
  865.     return (len);
  866. }
  867.  
  868.  
  869.  
  870.  
  871. /*------------------------------*/
  872. /*    itoLETTER        */
  873. /*------------------------------*/
  874. int itoLETTER (value, p, size)
  875. int        value;
  876. REGISTER char  *p;
  877. REGISTER int    size;
  878. {
  879.  
  880. /*
  881.  *    convert integer to upper letter value: 0,A,B,C,...,AA,AB,AC,...
  882.  */
  883.  
  884.     REGISTER int    i;
  885.     REGISTER int    j;
  886.     REGISTER int    aval;
  887.     char        c[20];
  888.  
  889.     aval = abs (value);
  890.     c[0] = EOS;
  891.     i = 1;
  892.  
  893.     /*
  894.      *   1 based:
  895.      *
  896.      *   0    0
  897.      *   1    A
  898.      *   25    Z
  899.      *   26    AA
  900.      *   51 AZ
  901.      *   52 AAA
  902.      *   ...
  903.      */
  904.     if (aval == 0)
  905.         c[i++] = '0';
  906.     else if (aval < 27)
  907.     {
  908.         c[i++] = aval - 1 + 'A';
  909.     }
  910.     else
  911.     {
  912.         do
  913.         {
  914.             c[i++] = ((aval - 1) % 26) + 'A';
  915.             aval = (aval - 1)  / 26;
  916.     
  917.         } while (aval > 0 && i <= size);
  918.     }
  919.  
  920.     if (value < 0 && i <= size)
  921.         c[i++] = '-';
  922.  
  923.     for (j = 0; j < i; ++j)
  924.         *p++ = c[i - j - 1];
  925.  
  926.     return (i);
  927. }
  928.  
  929.  
  930.  
  931. /*------------------------------*/
  932. /*    itoletter        */
  933. /*------------------------------*/
  934. int itoletter (value, p, size)
  935. int        value;
  936. REGISTER char  *p;
  937. REGISTER int    size;
  938. {
  939.  
  940. /*
  941.  *    convert integer to upper letter value: 0,a,b,c,...,aa,ab,ac,...
  942.  */
  943.  
  944.     REGISTER int    i;
  945.     REGISTER int    j;
  946.     REGISTER int    aval;
  947.     char        c[20];
  948.  
  949.     aval = abs (value);
  950.     c[0] = EOS;
  951.     i = 1;
  952.  
  953.     /*
  954.      *   1 based:
  955.      *
  956.      *   0    0
  957.      *   1    A
  958.      *   25    Z
  959.      *   26    AA
  960.      *   51 AZ
  961.      *   52 AAA
  962.      *   ...
  963.      */
  964.     if (aval == 0)
  965.         c[i++] = '0';
  966.     else if (aval < 27)
  967.     {
  968.         c[i++] = aval - 1 + 'a';
  969.     }
  970.     else
  971.     {
  972.         do
  973.         {
  974.             c[i++] = ((aval - 1) % 26) + 'a';
  975.             aval = (aval - 1)  / 26;
  976.     
  977.         } while (aval > 0 && i <= size);
  978.     }
  979.  
  980.     if (value < 0 && i <= size)
  981.         c[i++] = '-';
  982.  
  983.     for (j = 0; j < i; ++j)
  984.         *p++ = c[i - j - 1];
  985.  
  986.     return (i);
  987. }
  988.  
  989.  
  990.  
  991. /*------------------------------*/
  992. /*    min            */
  993. /*------------------------------*/
  994.  
  995. #ifdef min
  996. #undef min
  997. #endif
  998.  
  999. int min (v1, v2)
  1000. REGISTER int    v1;
  1001. REGISTER int    v2;
  1002. {
  1003.  
  1004. /*
  1005.  *    find minimum of two integer ONLY
  1006.  */
  1007.  
  1008.     return ((v1 < v2) ? v1 : v2);
  1009. }
  1010.  
  1011.  
  1012.  
  1013.  
  1014.  
  1015. /*------------------------------*/
  1016. /*    max            */
  1017. /*------------------------------*/
  1018.  
  1019. #ifdef max
  1020. #undef max
  1021. #endif
  1022.  
  1023. int max (v1, v2)
  1024. REGISTER int    v1;
  1025. REGISTER int    v2;
  1026. {
  1027.  
  1028. /*
  1029.  *    find maximum of two integers ONLY
  1030.  */
  1031.  
  1032.     return ((v1 > v2) ? v1 : v2);
  1033. }
  1034.  
  1035.  
  1036.  
  1037.  
  1038.  
  1039. /*------------------------------*/
  1040. /*    err_exit        */
  1041. /*------------------------------*/
  1042. void err_exit (code)
  1043. int code;
  1044. {
  1045.  
  1046. /*
  1047.  *    exit cleanly on fatal error (close files, etc). also handles normal
  1048.  *    exit.
  1049.  */
  1050.  
  1051.     if (err_stream != stderr && err_stream != (FILE *) 0)
  1052.     {
  1053.         /*
  1054.          *   not going to stderr (-o file)
  1055.          */
  1056.         fflush (err_stream);
  1057.         fclose (err_stream);
  1058.     }
  1059.     if (debugging && dbg_stream != stderr && dbg_stream != (FILE *) 0)
  1060.     {
  1061.         fflush (dbg_stream);
  1062.         fclose (dbg_stream);
  1063.     }
  1064.     if (out_stream != stdout && out_stream != (FILE *) 0)
  1065.     {
  1066.         /*
  1067.          *   not going to stdout (-l)
  1068.          */
  1069.         fflush (out_stream);
  1070.         fclose (out_stream);
  1071.     }
  1072.  
  1073.     if (hold_screen)
  1074.     {
  1075.         wait_for_char ();
  1076.     }
  1077.  
  1078.     exit (code);
  1079.  
  1080.     /*NOTREACHED*/
  1081. }
  1082.  
  1083.  
  1084.  
  1085. /*------------------------------*/
  1086. /*    wait_for_char        */
  1087. /*------------------------------*/
  1088. #ifdef GEMDOS
  1089. #include <osbind.h>
  1090. #endif
  1091.  
  1092. void wait_for_char ()
  1093. {
  1094. #ifdef GEMDOS
  1095.         printf ("enter any key..."); fflush (stdout);
  1096.         (void)Cconin ();
  1097. #endif
  1098. }
  1099.  
  1100.  
  1101.  
  1102.